package com.fbs.job.core.executor.impl;

import com.fbs.job.core.executor.FbsJobExecutor;
import com.fbs.job.core.handler.annotation.FbsJob;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.MethodIntrospector;
import org.springframework.core.annotation.AnnotatedElementUtils;

import java.lang.reflect.Method;
import java.util.Map;

public class FbsJobSpringExecutor extends FbsJobExecutor implements ApplicationContextAware, SmartInitializingSingleton, DisposableBean {

    private static final Logger logger = LoggerFactory.getLogger(FbsJobSpringExecutor.class);

    // ---------------------- applicationContext ----------------------
    private static ApplicationContext applicationContext;


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
                this.applicationContext = applicationContext;
    }

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    @Override
    public void afterSingletonsInstantiated() {
        initJobHandlerMethodRepository(applicationContext);

        // super start
        try {
            super.start();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private void initJobHandlerMethodRepository(ApplicationContext applicationContext) {
        if (applicationContext == null) {
            return;
        }

        String[] beanDefinitionNames = applicationContext.getBeanNamesForType(Object.class, false, true);
        for (String beanDefinitionName : beanDefinitionNames) {
            // get bean
            Object bean = null;

            Lazy onBean = applicationContext.findAnnotationOnBean(beanDefinitionName, Lazy.class);
            if (onBean!=null){
                logger.debug("fbs-job annotation scan, skip @Lazy Bean:{}", beanDefinitionName);
                continue;
            }else {
                bean = applicationContext.getBean(beanDefinitionName);
            }


            // filter method
            Map<Method, FbsJob> annotatedMethods =  MethodIntrospector.selectMethods(bean.getClass(), new MethodIntrospector.MetadataLookup<FbsJob>() {
                @Override
                public FbsJob inspect(Method method) {
                    return AnnotatedElementUtils.findMergedAnnotation(method,FbsJob.class);
                }
            });

            if (annotatedMethods==null || annotatedMethods.isEmpty()) {
                continue;
            }
            for (Map.Entry<Method, FbsJob> methodFbsJobEntry : annotatedMethods.entrySet()) {
                Method executeMethod = methodFbsJobEntry.getKey();
                FbsJob fbsJob = methodFbsJobEntry.getValue();
                // register
                registerJobHandler(fbsJob, bean, executeMethod);

            }

        }

    }
}
